//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2013 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_FUNCTORS_TRANSFORM_MATH_H_
#define _BUOLA_FUNCTORS_TRANSFORM_MATH_H_

#include <buola/functors/transform/unary.h>

namespace buola { namespace fn {

///\addtogroup functors
///@{

///\name Mathematic unary transformations
//@{

/////////////////////////////////////////////////////////////////////////////////////////////////
///
/// absolute value transformation
///
/// Evaluated with a single argument, returns the absolute value of the argument
///
/////////////////////////////////////////////////////////////////////////////////////////////////
struct AAbs : public GUnaryTransform
{
    ///returns abs(\p pVal )
    template<typename tParam>
    tParam operator()(const tParam &pVal) const
    {
        return abs(pVal);
    }
};

/////////////////////////////////////////////////////////////////////////////////////////////////
///
/// sine transformation
///
/// Evaluated with a single argument, returns the sine of the argument
///
/////////////////////////////////////////////////////////////////////////////////////////////////
struct ASin : public GUnaryTransform
{
    ///returns sin(\p pVal )
    template<typename tParam>
    tParam operator()(const tParam &pVal) const
    {
        return sin(pVal);
    }
};

/////////////////////////////////////////////////////////////////////////////////////////////////
///
/// cosine transformation
///
/// Evaluated with a single argument, returns the cosine of the argument
///
/////////////////////////////////////////////////////////////////////////////////////////////////
struct ACos : public GUnaryTransform
{
    ///returns sin(\p pVal )
    template<typename tParam>
    tParam operator()(const tParam &pVal) const
    {
        return cos(pVal);
    }
};

/////////////////////////////////////////////////////////////////////////////////////////////////
///
/// logarithm transformation
///
/// Evaluated with a single argument, returns the natural logarithm of the argument
///
/////////////////////////////////////////////////////////////////////////////////////////////////
struct ALog : public GUnaryTransform
{
    ///returns sin(\p pVal )
    template<typename tParam>
    tParam operator()(const tParam &pVal) const
    {
        return log(pVal);
    }
};

/////////////////////////////////////////////////////////////////////////////////////////////////
///
/// exponential transformation
///
/// Evaluated with a single argument, returns the value of the exponential function at the argument
///
/////////////////////////////////////////////////////////////////////////////////////////////////
struct AExp : public GUnaryTransform
{
    ///returns sin(\p pVal )
    template<typename tParam>
    tParam operator()(const tParam &pVal) const
    {
        return exp(pVal);
    }
};

/////////////////////////////////////////////////////////////////////////////////////////////////
///
/// square root transformation
///
/// Evaluated with a single argument, returns the square root of the argument
///
/////////////////////////////////////////////////////////////////////////////////////////////////
struct ASqrt : public GUnaryTransform
{
    ///returns sin(\p pVal )
    template<typename tParam>
    tParam operator()(const tParam &pVal) const
    {
        return sqrt(pVal);
    }
};

/////////////////////////////////////////////////////////////////////////////////////////////////
///
/// square transformation
///
/// Evaluated with a single argument, returns the square of the argument
///
/////////////////////////////////////////////////////////////////////////////////////////////////
struct ASq : public GUnaryTransform
{
    ///returns sin(\p pVal )
    template<typename tParam>
    tParam operator()(const tParam &pVal) const
    {
        return sq(pVal);
    }
};

/////////////////////////////////////////////////////////////////////////////////////////////////
///
/// pow-constant transformation
///
/// Evaluated with a single argument, returns the argument plus the constant provided 
/// in the constructor
///
/////////////////////////////////////////////////////////////////////////////////////////////////
template<typename tType>
struct APowConstant : public GUnaryTransform
{
    ///initialises the comparison constant from its argument
    explicit APowConstant(const tType &pVal)
        :   mVal(pVal)
    {}
    
    ///initialises the comparison constant from its argument (move version)
    explicit APowConstant(tType &&pVal)
        :   mVal(std::move(pVal))
    {}
    
    ///returns \p pVal+mVal
    template<typename tParam>
    tParam operator()(const tParam &pVal) const
    {
        return pow(pVal,mVal);
    }
    
private:
    tType mVal;
};

//@}

///@}

/*namespace fn*/ } /*namespace buola*/ }

#endif
